#include "Auction.h"

unsigned int Auction::last_AuctionID = 11000;

void Auction::addBid(Bid b){
	int bid_index = -1;
	vector<Bid> itemBids;
	bool lowValueBid = false;

	for(size_t i = 0; i < bids.size(); i++) {
		//Find every bid for that item
		if(bids[i].getItem() == b.getItem()) {
			itemBids.push_back(bids[i]);
		}

		//If the bid on that item with that value already exists
		if(bids[i].getValue() == b.getValue()) {
			bid_index = i;
			throw ExistentBid();
		}
	}

	//If the bid on the selected item doesn't exist with the chosen value
	if(bid_index == -1) {
		// check if any of the bids have a higher value than the value of Bid b
		for(size_t j = 0; j < itemBids.size(); j++) {
			if(itemBids[j].getValue() >= b.getValue())
				lowValueBid = true;
		}

		if(lowValueBid == false) {
			bids.push_back(b);
			updateHighestBids(b);
		}
		else
			cout << "You must place a bid with a higher value than the current highest bid on the selected item." << endl;
	}
}

void Auction::addItem(Item _item){
	for(size_t i = 0; i < items.size(); i++) {
		if(items[i] == _item)
			throw ExistentItem();
	}

	items.push_back(_item);

	if(highest_bids.size() == 0)
		initializeHighestBids();
	else {
		Bid b;
		b.setItem(_item);
		Date d(0,0,0,0,0);
		highest_bids.push_back(b);
	}
}

void Auction::addParticipant(Client client) {
	for(size_t i = 0; i < participants.size(); i++) {
		if(participants[i] == client)
			throw ExistentAuctionParticipant();
	}

	participants.push_back(client);
}

Item Auction::searchItem(unsigned int itemID) {
	for(size_t i = 0; i < items.size(); i++) {
		if(items[i].getID() == itemID)
			return items[i];
	}

	throw NonexistentItem();
}

void Auction::initializeHighestBids() {
	for(size_t i = 0; i < items.size(); i++) {
		Bid b;
		b.setItem(items[i]);
		Date d(0,0,0,0,0);
		highest_bids.push_back(b);
	}
}

void Auction::updateHighestBids(Bid b) {
	//called by addBid
	//addBid already checks if the bid value is higher or not, so no need to check here.
	for(size_t i = 0; i < highest_bids.size(); i++) {
		if(highest_bids[i].getItem() == b.getItem()) {
			highest_bids[i] = b;
		}
	}
}

void Auction::save(string filename, ofstream & out) {
	//ofstream out;
	//out.open(filename.c_str(), fstream::app);

	out << "[AUCTION]" << endl;
	out << this->getStartDate().get_day() << endl;
	out << this->getStartDate().get_month() << endl;
	out << this->getStartDate().get_year() << endl;
	out << this->getStartDate().get_hour() << endl;
	out << this->getStartDate().get_minute() << endl;

	out << this->getEndDate().get_day() << endl;
	out << this->getEndDate().get_month() << endl;
	out << this->getEndDate().get_year() << endl;
	out << this->getEndDate().get_hour() << endl;
	out << this->getEndDate().get_minute() << endl;

	out << "[ITEMS]" << endl;
	for (size_t m = 0; m < this->getItems().size(); m++) {
		out << this->getItems()[m].getID() << endl;
	}

	out << "[/ITEMS]" << endl;
	out << this->getBids().size() << endl;

	for (size_t b = 0; b < this->getBids().size(); b++) {
		out << "[BID]" << endl;
		out << this->getBids()[b].getBidder().getID() << endl;
		out << this->getBids()[b].getDate().get_day() << endl;
		out << this->getBids()[b].getDate().get_month() << endl;
		out << this->getBids()[b].getDate().get_year() << endl;
		out << this->getBids()[b].getDate().get_hour() << endl;
		out << this->getBids()[b].getDate().get_minute() << endl;
		out << this->getBids()[b].getItem().getID() << endl;
		out << this->getBids()[b].getValue() << endl;
		out << "[/BID]" << endl;
	}

	out << "[/AUCTION]" << endl;
}

void Auction::showAuction(){
	cout << "Auction - ID: " << auctionID << endl;
	cout << "Starting date: ";
	starting_date.displayDate();
	cout << endl;

	if(!(ending_date.isDateSet())) {//equivalent is date==null
		cout << "Ending date: ";
		ending_date.displayDate();
		cout << endl;
	} else {
		cout << "No ending date set yet." << endl;
	}

	cout << "------------------------------------------------------------" << endl;
	for(size_t i = 0; i < items.size(); i++){
		items[i].showItem();
	}

	if(bids.size() > 0) {
		//shows only the highest bids to reduce spam
		cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
		cout << "Highest bids placed until the moment\n" << endl;

		for(size_t i = 0; i < highest_bids.size(); i++) {
			cout << "Item Bidded on: " << highest_bids[i].getItem().getName() << endl;

			if(highest_bids[i].getValue() == 0.0) {
				cout << "No bids yet on this item." << endl;
			} else {
				cout << "Bidder Name: " << highest_bids[i].getBidder().getName() <<endl;
				cout << "Date it was placed: "; highest_bids[i].getDate().displayDate(); cout <<endl;
				cout << "Value of the bid: " << highest_bids[i].getValue() << endl;
			}
			cout << endl;
		}
	} else
		cout << "No current bids yet." << endl;

	cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
	cout << "************************************************************" << endl;
}

void Auction::setIsEnded(bool _isEnded) {
	isEnded = _isEnded;

	if(isEnded == true) {
		//For every item in the auction (vector items)
		// 1) Check its highest_bid (vector highest_bids)
		for(size_t i = 0; i < highest_bids.size(); i++) {
			if(highest_bids[i].getValue() > 0.0) {
				//Item goes to client <-- setOwner
				// highest_bids[i].getItem() == items[i] <-- due to the way it is initialized.
				string new_owner = highest_bids[i].getBidder().getID();
				items[i].setOwner(new_owner);
			}
		}
	}
}
